# -*- coding: utf-8 -*-

import pygtk
pygtk.require('2.0')
import gtk, os

import wave
import numpy as np
import matplotlib.pyplot as plt

import ft
from sigutil import frames2signal, signal2frames, treshold, rootMeanSqr
from figconv import fig2img

import wnds.gladewnd

from multiprocessing import Process



class AppWnd(wnds.gladewnd.GladeWnd):
    """Класс главного окна программы."""
    
    def __init__(self):
        # этот файл лежит в папке tuman/wnds
        wndsFolderPath = os.path.dirname(__file__)
        # абсолютный путь к папке программы
        self.path = os.path.dirname(wndsFolderPath)
        pathToUi = os.path.join(self.path, 'wnds/main.glade')
        super(AppWnd, self).__init__(pathToUi)
        # наполняем списки значениями
        self.fillLists()
        self.connect_signals({
            'on_wnd_top_destroy': lambda widget: self.quit(),
            'on_btn_go_clicked': lambda widget: self.transform(),
            'on_btn_apply_clicked': lambda widget: self.changes(),
            'on_menuitem_open_activate': lambda widget: self.openSignal(),
            'on_menuitem_save_activate': lambda widget: self.saveSignal(),
            'on_menuitem_quit_activate': lambda widget: self.destroy(),
            'on_menuitem_about_activate': lambda widget: self.about()
        })
        # инициализируем атрибуты
        self.sigpath = None  # абсолютный путь до файла с сигналом
        self.resigpath = None  # абсолютный путь до файла, в который сохранятся
        self.signal = None  # исходный сигнал
        self.noiseSignal = None  # зашумлённый сигнал
        self.spectrum = None  # спектр исходного сигнала
        self.fspectrun = None  # отфильтрованный спектр
        self.wnd_top.show()
        
    def fillLists(self):
        """Наполняет списки на форме значениями."""
        
        self.fillListStr(self.c_transforms, ft.supportedTransforms)
        self.fillListStr(self.c_treshold, [u'hard', u'linear', u'Vidakovich'])
    
    def quit(self):
        gtk.main_quit()
    
    def transform(self):
        """Выполняет преобразования сигнала."""
        self.readSignal()
        self.noising()
        transFuncs = self.getTransfFuncs()
        self.spectrum = transFuncs[0](self.noiseSignal)
        self.filtering()
        # восстанавливаем сигнал
        self.resignal = transFuncs[1](self.fspectrum)
        # рисуем результат
        self.showplot()
   
    def changes(self):
        self.filtering()
        invTransf = self.getTransfFuncs()[1]
        self.resignal = invTransf(self.fspectrum)
        self.showplot()
    
    def noising(self):
        noiseCoeff = self.spin_noise.get_value()
        self.noiseSignal = np.array(self.signal)
        if noiseCoeff > 0:
            self.noiseSignal += noiseCoeff * np.random.randn(self.signal.size)
    
    def filtering(self):
        self.fspectrum = np.array(self.spectrum)
        # сокращение
        reduct = float(self.spin_reduction.get_value_as_int()) / 100
        if reduct > 0:
            reductMargin = int(round(reduct * (1 << 16)))
            self.fspectrum[reductMargin:] = 0
        # пороговая обработка
        treshName = self.c_treshold.get_active_text()
        treshVal = int(self.spin_treshlod.get_value_as_int())
        if treshVal > 0:
            treshold(self.fspectrum, treshVal, treshName)

    def showplot(self):
        fig = plt.figure(figsize = (16, 10))
        
        plot = fig.add_subplot(311)
        plot.set_title(u'Сигнал')
        plot.plot(self.noiseSignal, 'r')
        plot.plot(self.signal, 'b')
        plot.axis('tight')
        
        plot = fig.add_subplot(312)
        plot.set_title(u'Спектр')
        plot.plot(self.fspectrum)

        plot = fig.add_subplot(313)
        rms = str(rootMeanSqr(self.signal, self.resignal))
        plot.set_title(u'Восстановленный сигнал (' + rms + ')')
        plot.plot(self.signal)
        plot.plot(self.resignal, 'r')
        fig2img(fig).show()

    def openSignal(self):
        od = gtk.FileChooserDialog(parent = self.wnd_top, 
            action = gtk.FILE_CHOOSER_ACTION_OPEN,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
                gtk.STOCK_OPEN, gtk.RESPONSE_OK
            )
        )
        self.addFilters(od)
        resp = od.run()
        if resp == gtk.RESPONSE_OK:
            self.sigpath = od.get_filename()
        od.destroy()

    
    def saveSignal(self):
        sd = gtk.FileChooserDialog(parent = self.wnd_top, 
            action = gtk.FILE_CHOOSER_ACTION_SAVE,
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, 
                gtk.STOCK_SAVE, gtk.RESPONSE_OK
            )
        )
        self.addFilters(sd)
        resp = sd.run()
        if resp == gtk.RESPONSE_OK:
            self.resigpath = sd.get_filename()
        sd.destroy()
        self.writeSignal()
    
    def destroy(self):
        self.wnd_top.destroy()
    
    def about(self):
        md = gtk.MessageDialog(self.wnd_top, gtk.DIALOG_DESTROY_WITH_PARENT, 
            gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, u'Туман'
        )
        md.format_secondary_text(u'Теплинский Кирилл\n2010г')
        md.run()
        md.destroy()

    def addFilters(self, fcd):
        # все файлы
        fileFilter = gtk.FileFilter()
        fileFilter.set_name('All files')
        fileFilter.add_pattern('*.*')
        fcd.add_filter(fileFilter)
        # wav-ки
        fileFilter = gtk.FileFilter()
        fileFilter.set_name('WAV files')
        fileFilter.add_mime_type('audio/x-wav')
        fcd.add_filter(fileFilter)
    
    def readSignal(self):
        w = wave.open(self.sigpath)
        # получаем характеристики файла
        self.nchannels = w.getnchannels()
        self.framerate = w.getframerate()
        self.sampwidth = w.getsampwidth()
        # читаем сигнал
        frames = w.readframes(1 << 16)
        w.close()
        self.signal = np.array(list(frames2signal(frames, self.sampwidth)))
        # уменьшаем разрешение сигнала, чтобы влазил в 16 бит
        self.signal /= 1 << 16

    def writeSignal(self):
        w = wave.open(self.resigpath, 'w')
        w.setnchannels(1)
        w.setframerate(22050)
        w.setsampwidth(2)
        frames = ''.join(signal2frames(self.resignal, 2))
        w.writeframes(frames)
        w.close()
    
    def getTransfFuncs(self):
        tn = self.c_transforms.get_active_text()
        if tn == 'Fast Walsh':
            return (ft.fwht, ft.ifwht)
        elif tn == 'Fast Haar':
            return (ft.fwth, ft.ifwth)
        else:
            return (ft.fwtd, ft.ifwtd)
